package com.yuehuanghun.admin.core.service.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.yuehuanghun.admin.core.config.DataScope;
import com.yuehuanghun.admin.core.config.UserConstants;
import com.yuehuanghun.admin.core.config.util.SecurityUtils;
import com.yuehuanghun.admin.core.config.util.UserUtils;
import com.yuehuanghun.admin.core.domain.SysDept;
import com.yuehuanghun.admin.core.domain.SysPost;
import com.yuehuanghun.admin.core.domain.SysRole;
import com.yuehuanghun.admin.core.domain.SysUser;
import com.yuehuanghun.admin.core.domain.SysUserPost;
import com.yuehuanghun.admin.core.domain.SysUserRole;
import com.yuehuanghun.admin.core.mapper.SysDeptMapper;
import com.yuehuanghun.admin.core.mapper.SysPostMapper;
import com.yuehuanghun.admin.core.mapper.SysRoleMapper;
import com.yuehuanghun.admin.core.mapper.SysUserMapper;
import com.yuehuanghun.admin.core.mapper.SysUserPostMapper;
import com.yuehuanghun.admin.core.mapper.SysUserRoleMapper;
import com.yuehuanghun.admin.core.service.ISysConfigService;
import com.yuehuanghun.admin.core.service.ISysUserService;
import com.yuehuanghun.framework.exception.ValidateException;
import com.yuehuanghun.framework.util.StringUtils;
import com.yuehuanghun.mybatis.milu.criteria.LambdaQueryPredicate;
import com.yuehuanghun.mybatis.milu.ext.BaseServiceImpl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;

/**
 * 用户 业务层处理
 * 
 * @author yadmin
 */
@Service
public class SysUserServiceImpl extends BaseServiceImpl<SysUser, Long, SysUserMapper> implements ISysUserService {
	private static final Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class);

	@Autowired
	private SysUserMapper userMapper;

	@Autowired
	private SysRoleMapper roleMapper;

	@Autowired
	private SysPostMapper postMapper;

	@Autowired
	private SysUserRoleMapper userRoleMapper;

	@Autowired
	private SysUserPostMapper userPostMapper;

	@Autowired
	private ISysConfigService configService;
	
	@Autowired
	private SysDeptMapper deptMapper;

	/**
	 * 根据条件分页查询用户列表
	 * 
	 * @param user 用户信息
	 * @return 用户信息集合信息
	 */
	@SuppressWarnings("unchecked")
	@Override
	public List<SysUser> getUserList(SysUser user) {
		String beginTimeStr = (String)user.getParams().get("timeBegin");
		String endTimeStr = (String)user.getParams().get("timeEnd");
		Date beginTime, endTime;
		if(StringUtils.isNotBlank(beginTimeStr)) {
			beginTime = DateUtil.parseDate(beginTimeStr);
		} else {
			beginTime = null;
		}
		if(StringUtils.isNotBlank(endTimeStr)) {
			endTime = DateUtil.endOfDay(DateUtil.parseDate(endTimeStr));
		} else {
			endTime = null;
		}
		
		Long scopeUser;
		Set<Long> scopeDeptIds; //数据范围过滤参数
		
		DataScope dataScope = UserUtils.getCurrentUserDataScope();
		if(dataScope.isDeptScope()) {
			if(dataScope.getDeptIds() != null) {
				if(dataScope.getDeptIds().isEmpty()) {
					return Collections.emptyList();
				} else {
					scopeDeptIds = dataScope.getDeptIds();
				}
			} else {
				scopeDeptIds = null;
			}
			scopeUser = null;
		} else {
			scopeUser = dataScope.getUserId();
			scopeDeptIds = null;
		}
		
		List<Long> filterDeptIds; //入参过滤参数
		if(user.getDeptId() != null && user.getDeptId() > 0) {
			filterDeptIds =  new ArrayList<>();
			filterDeptIds.add(user.getDeptId());
			List<Long> deptIds = deptMapper.findByLambdaCriteria(p -> p.select(SysDept::getDeptId).contain(SysDept::getAncestors, ":" + user.getDeptId() + ":"), Long.class);
			filterDeptIds.addAll(deptIds);
		} else {
			filterDeptIds = null;
		}
		
		Collection<Long> condDeptIds; //mapper查询过滤参数
		if(scopeDeptIds == null && filterDeptIds == null) {
			condDeptIds = null;
		} else if(scopeDeptIds == null) {
			condDeptIds = filterDeptIds;
		} else if(filterDeptIds == null) {
			condDeptIds = scopeDeptIds;
		} else {
			condDeptIds = CollUtil.intersection(scopeDeptIds, filterDeptIds); //取交集
		}	
		
		Consumer<LambdaQueryPredicate<SysUser>> predicate = p -> {
			p.eq(SysUser::getDelFlag, "0")
			 .contain(SysUser::getUserName, user.getUserName())
			 .contain(SysUser::getPhonenumber, user.getPhonenumber())
			 .eq(SysUser::getStatus, user.getStatus())
			 .gte(SysUser::getCreateTime, beginTime)
			 .lte(SysUser::getCreateTime, endTime)
			 .eq(SysUser::getUserId, scopeUser)
			 .in(SysUser::getDeptId, condDeptIds);
		};		
		
		List<SysUser> users = userMapper.findByLambdaCriteria(predicate);
		if(!users.isEmpty()) {
			List<Long> deptIds = users.stream().map(SysUser::getDeptId).filter(Objects::nonNull).collect(Collectors.toList());
			if(!deptIds.isEmpty()) {
				Map<Long, SysDept> deptMap = deptMapper.findByIds(deptIds).stream().collect(Collectors.toMap(SysDept::getDeptId, Function.identity()));
				users.forEach(item -> item.setDept(deptMap.get(item.getDeptId())));
			}
		}
		
		return users;
	}

	/**
	 * 通过用户名查询用户
	 * 
	 * @param userName 用户名
	 * @return 用户对象信息
	 */
	@Override
	public SysUser getUserByUserName(String userName) {
		return userMapper.findByUserName(userName);
	}

	/**
	 * 查询用户所属角色组
	 * 
	 * @param userName 用户名
	 * @return 结果
	 */
	@Override
	public String getUserRoleGroup(String userName) {
		List<SysRole> list = roleMapper.findByUsersUserNameAndDelFlag(userName, "0");
		StringBuffer idsStr = new StringBuffer();
		for (SysRole role : list) {
			idsStr.append(role.getRoleName()).append(",");
		}
		if (StringUtils.isNotEmpty(idsStr.toString())) {
			return idsStr.substring(0, idsStr.length() - 1);
		}
		return idsStr.toString();
	}

	/**
	 * 查询用户所属岗位组
	 * 
	 * @param userName 用户名
	 * @return 结果
	 */
	@Override
	public String getUserPostGroup(String userName) {
		return postMapper.findByUsersUserName(userName).stream().map(SysPost::getPostName)
				.collect(Collectors.joining(","));
	}

	/**
	 * 校验用户名称是否唯一
	 * 
	 * @param userName 用户名称
	 * @return 结果
	 */
	@Override
	public String checkUserNameUnique(String userName) {
		return userMapper.countByUserName(userName) > 0 ?  UserConstants.NOT_UNIQUE : UserConstants.UNIQUE;
	}

	/**
	 * 校验用户名称是否唯一
	 *
	 * @param user 用户信息
	 * @return
	 */
	@Override
	public String checkPhoneUnique(SysUser user) {
		Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
		SysUser info = userMapper.findFirstByPhonenumber(user.getPhonenumber());
		if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
			return UserConstants.NOT_UNIQUE;
		}
		return UserConstants.UNIQUE;
	}

	/**
	 * 校验email是否唯一
	 *
	 * @param user 用户信息
	 * @return
	 */
	@Override
	public String checkEmailUnique(SysUser user) {
		Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
		SysUser info = userMapper.findFirstByEmail(user.getEmail());
		if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
			return UserConstants.NOT_UNIQUE;
		}
		return UserConstants.UNIQUE;
	}

	/**
	 * 校验用户是否允许操作
	 * 
	 * @param user 用户信息
	 */
	@Override
	public void checkUserAllowed(SysUser user) {
		if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin()) {
			throw new ValidateException("不允许操作超级管理员用户");
		}
	}

	/**
	 * 新增保存用户信息
	 * 
	 * @param user 用户信息
	 * @return 结果
	 */
	@Override
	@Transactional
	public int insertUser(SysUser user) {
		// 新增用户信息
		int rows = userMapper.insert(user);
		// 新增用户岗位关联
		insertUserPost(user);
		// 新增用户与角色管理
		insertUserRole(user);
		return rows;
	}

	/**
	 * 修改保存用户信息
	 * 
	 * @param user 用户信息
	 * @return 结果
	 */
	@Override
	@Transactional
	public int updateUser(SysUser user) {
		Long userId = user.getUserId();
		// 删除用户与角色关联
		userRoleMapper.deleteByUserId(userId);
		// 新增用户与角色管理
		insertUserRole(user);
		// 删除用户与岗位关联
		userPostMapper.deleteByUserId(userId);
		// 新增用户与岗位管理
		insertUserPost(user);
		int effect = userMapper.updateById(user);
		UserUtils.clearCache(user.getUserName());
		return effect;
	}

	/**
	 * 修改用户头像
	 * 
	 * @param userName 用户名
	 * @param avatar   头像地址
	 * @return 结果
	 */
	@Override
	public boolean updateUserAvatar(String userName, String avatar) {
		SysUser updateParam = new SysUser();
		updateParam.setAvatar(avatar);
		return userMapper.updateByLambdaCriteria(updateParam, p -> p.eq(SysUser::getUserName, userName)) > 0;
	}

	/**
	 * 重置用户密码
	 * 
	 * @param userName 用户名
	 * @param password 密码
	 * @return 结果
	 */
	@Override
	public int resetUserPwd(String userName, String password) {
		SysUser updateParam = new SysUser();
		updateParam.setPassword(password);
		return userMapper.updateByLambdaCriteria(updateParam, p -> p.eq(SysUser::getUserName, userName));
	}

	/**
	 * 新增用户角色信息
	 * 
	 * @param user 用户对象
	 */
	public void insertUserRole(SysUser user) {
		Long[] roles = user.getRoleIds();
		if (StringUtils.isNotNull(roles)) {
			// 新增用户与角色管理
			List<SysUserRole> list = new ArrayList<>();
			for (Long roleId : roles) {
				SysUserRole ur = new SysUserRole();
				ur.setUserId(user.getUserId());
				ur.setRoleId(roleId);
				list.add(ur);
			}
			if (!list.isEmpty()) {
				userRoleMapper.batchInsert(list);
			}
		}
	}

	/**
	 * 新增用户岗位信息
	 * 
	 * @param user 用户对象
	 */
	public void insertUserPost(SysUser user) {
		Long[] posts = user.getPostIds();
		if (StringUtils.isNotNull(posts)) {
			// 新增用户与岗位管理
			List<SysUserPost> list = new ArrayList<>();
			for (Long postId : posts) {
				SysUserPost up = new SysUserPost();
				up.setUserId(user.getUserId());
				up.setPostId(postId);
				list.add(up);
			}
			if (!list.isEmpty()) {
				userPostMapper.batchInsert(list);
			}
		}
	}

	/**
	 * 通过用户ID删除用户
	 * 
	 * @param userId 用户ID
	 * @return 结果
	 */
	@Override
	@Transactional
	public int deleteUserById(Long userId) {
		// 删除用户与角色关联
		userRoleMapper.deleteByUserId(userId);
		// 删除用户与岗位表
		userPostMapper.deleteByUserId(userId);
		return userMapper.deleteById(userId);
	}

	/**
	 * 批量删除用户信息
	 * 
	 * @param userIds 需要删除的用户ID
	 * @return 结果
	 */
	@Override
	@Transactional
	public int deleteUserByIds(Long[] userIds) {
		for (Long userId : userIds) {
			checkUserAllowed(new SysUser(userId));
		}
		// 删除用户与角色关联
		userRoleMapper.deleteByUserIdIn(userIds);
		// 删除用户与岗位关联
		userPostMapper.deleteByUserIdIn(userIds);
		
		SysUser updateParam = new SysUser();
		updateParam.setDelFlag("2"); //逻辑删除
		return userMapper.updateByLambdaCriteria(updateParam, p -> p.in(SysUser::getUserId, userIds));
	}

	/**
	 * 导入用户数据
	 * 
	 * @param userList        用户数据列表
	 * @param isUpdateSupport 是否更新支持，如果已存在，则进行更新数据
	 * @param operName        操作用户
	 * @return 结果
	 */
	@Override
	public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName) {
		if (StringUtils.isNull(userList) || userList.isEmpty()) {
			throw new ValidateException("导入用户数据不能为空！");
		}
		int successNum = 0;
		int failureNum = 0;
		StringBuilder successMsg = new StringBuilder();
		StringBuilder failureMsg = new StringBuilder();
		String password = configService.getConfigByKey("sys.user.initPassword");
		for (SysUser user : userList) {
			try {
				// 验证是否存在这个用户
				SysUser u = userMapper.findByUserName(user.getUserName());
				if (StringUtils.isNull(u)) {
					user.setPassword(SecurityUtils.encryptPassword(password));
					user.setCreateBy(operName);
					this.insertUser(user);
					successNum++;
					successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 导入成功");
				} else if (isUpdateSupport) {
					user.setUpdateBy(operName);
					this.updateUser(user);
					successNum++;
					successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 更新成功");
				} else {
					failureNum++;
					failureMsg.append("<br/>" + failureNum + "、账号 " + user.getUserName() + " 已存在");
				}
			} catch (Exception e) {
				failureNum++;
				String msg = "<br/>" + failureNum + "、账号 " + user.getUserName() + " 导入失败：";
				failureMsg.append(msg + e.getMessage());
				log.error(msg, e);
			}
		}
		if (failureNum > 0) {
			failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
			throw new ValidateException(failureMsg.toString());
		} else {
			successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
		}
		return successMsg.toString();
	}
}
